package com.charging.business.gantry;

import com.sun.jna.Library;
import com.sun.jna.Structure;

import java.util.Arrays;
import java.util.List;

/**
 * @author JerryLu
 * @date 2024/8/10 16:39
 * @description 计费模块动态库映射类
 */
public interface Feecalc extends Library {
    //    Feecalc INSTANCE = (Feecalc) Native.loadLibrary(PropertiesUtils.getValue("path"), Feecalc.class);

    /**
     * 初始化
     * 更新包解压后，包中的文件会保持相对路径关系,初始化时,计费模块根据当前门架编码查询收费单元组合并加载相应的费率参数,完成自检,自检正常则
     * 返回0,否则返回错误码。耗时要求：不大于3秒。
     * 注：自检含省份参数完整性有效性检查、入参的有效性判断及计费模块的其它
     * 初始化动作的 结果 判断。
     *
     * @param curTollGantry 输入 当前门架编码，为null 时表示全省应用
     * @param soPath        输入 计费模块so库文件所在绝对路径（含末尾的“/”如：“/etc_run /lib/feelib/cur/feecalc_province32_3220190830001_x86/”
     * @return 返回值：NO_ERROR(0)，正常；
     * 返回值：<0 错误见函数返回值定义。
     * @author JerryLu
     * @date 2024/8/10 16:41
     */
    int init(byte[] curTollGantry, byte[] soPath);

    /**
     * 释放计费模块占用的资源
     *
     * @return 返回值：NO_ERROR(0) 0)，正常
     * 返回值：<0 错误见函数返回值定义。
     */
    int deInit();

    /**
     * 获取计费模块版本
     * 获取 费率库 版本信息 ，版本格式与文件名中的版本格式一致。
     * 同时获取数据结构的版本号，
     * 部中心统一维护数据结构版本号 ，计费模块
     * 需返回计费模块所用的数据结构版本号 ，用于门架系统进行模块接口兼容
     * 性判断。本文的数据结构版本号定为‘20191028001'。
     *
     * @param version     输出 计费模块版本信息缓存地址
     * @param verLen      输入 计费模块 版本信息缓存长度
     * @param dataVersion 输出 数据版本信息缓存地址
     * @param dataVerLen  输入 数据版本信息缓存长度
     * @return 返回值：NO_ERROR(0)，正常；
     * 返回值：<0 错误见函数返回值定义。
     */
    int getLibVersion(byte[] version, int verLen, byte[] dataVersion, int dataVerLen);

    /**
     * 获取计费参数版本
     * 格式为“2 位省份编码 +yyyymmdd+3 位顺序号”
     *
     * @param version 输出 版本信息缓存地址
     * @param verLen  输入 版本信息缓存长度
     * @return 返回值：NO_ERROR(0)，正常；
     * 返回值：<0 错误见函数返回值定义。
     */
    int getFeeDataVersion(byte[] version, int verLen);

    /**
     * 查询费率（收费站编码）
     *
     * @param tradingInfo 输入 交易信息
     * @param feeInfo     输出 费率查询结果，费率信息
     * @return 返回值：NO_ERROR(0)，正常；
     * 返回值：<0 错误见函数返回值定义。
     * 错误代码及原因
     * //省份计费参数缺失
     *
     *  -20,  PARMFILE_ABSENT ----》请检查当前门架和过站时间是否提供
     *
     * //省份计费参数存在但无效
     *
     *  -21,  PARMFILE_INVALID ----》请检查提供的门架是否在FPETCGANTRY.TXT里面存在
     *
     * //输入参数不正常
     *
     * -22,  INVALID_IN_PARM ----》请检查参数格式是否正确
     *
     * //申请内存失败
     *
     * -23,  APPLY_MEM_FAILED ----》系统内存用完了,申请失败
     *
     * //门架不存在
     *
     * -24,  GANTRY_NO_EXIST ----》路径拟合出来的门架不存在
     *
     * //收费单元不存在
     *
     *  -25,  INTERVAL_NO_EXIST ----》根据门架找的收费单元在FPTOLLINTERVAL.TXT里面是否存在，或者过站时间是否参数的开始时间之后
     *
     * //版本为空
     *
     *  -26,  VERSION_FAILED ----》检查请求参数里面的过站时间是在对应参数FPETCGANTRY.TXT里面的开始时间（STARTTIME）
     *
     * //初始化失败
     *
     * -27,  INIT_FAILED ----》初始化时，传入的路径参数不对
     *
     * //路径拟合失败
     *
     * -28,  INIT_THE_PATH_FAILED ----》路径拟合初始化失败
     *
     * //路径拟合失败
     *
     *  -29,  GET_THE_PATH_FAILED ----》调用路径拟合不成功，如没有拟合到路径，或者路径拟合报错等
     *
     * 路径拟合提示：路径拟合只会根据当前时间去加载2个版本，一个是当前时间之前的版本，一个是当前时间之后的版本，比如今天是2020年11月3号，参数有2个版本 ，20200809，20200930，那么只会加载20200930，如果curPassTime是20200904的话，就不能计算出来
     *
     * //时间格式不对
     *
     * -30,  TIME_TYPE_FAILED = ----》初始化时时间格式不正确
     *
     * //初始化门架不对
     *
     * -31,  INIT_INTERVAL_FAILED ----》初始化时门架不存在
     *
     * //初始化收费单元不对
     *
     * -32,  INIT_TOLLINTERVAL_FAILED ----》初始化的时候没有读到收费单元信息，就是收费单元参数文件不存在
     *
     * //重复计费
     *
     *  -33,  DUPLICATE_FEE_CAL_FAILED
     *
     * //当前门架拟合大于反向门架拟合里程
     *
     *  -34,  MILEAGE_GET_THEPATH_FAILED
     *
     * //反向干扰OppositeGantryHex
     *  -35,  OPPOSITE_HEX_SAME_FAILED
     *
     * //超速
     *
     * -36,Speed greater than
     *
     * //省界入口反向干扰
     *
     * -37,current Gantry is enStation 当前门架是省界入口门架
     *
     * //省界出口反向干扰
     *
     * -38,current Gantry is exStation。当前门架是省界出口门架，且上一门架是外省门架 。
     */
    int getFee(TradingInfo.ByReference tradingInfo, FeeInfo.ByReference feeInfo);

    public static class TradingInfo extends Structure {
        /**
         * 当前收费门架编码，当初始化函数中的当前门架编码为null时，应支持全省所有门架的费用查询（含代收）；
         * 初始化函数中的当前门架编码不为null时，该字段与初始化函数中的当前门架编码相等。
         */
        public byte[] curTollGantry = new byte[20];
        /**
         * 当前收费门架经过时间，如：“2019-08-17T15:32:58“
         */
        public byte[] curPassTime = new byte[20];
        /**
         * 卡片或标签上获得的出入口车道状态，
         * 0x00-保留，
         * 0x01-封闭E/M混合入口，
         * 0x02-封闭E/M混合出口，
         * 0x03-封闭ETC入口，
         * 0x04-封闭ETC出口，
         * 0x05-E/M混合开放式，
         * 0x06-ETC开放式，
         * 0x07～15自定义，
         * 0x16-自助发卡，
         * 0x17～255保留给未来使用，十六进制编码。
         */
        public int laneStatus;
        /**
         * 卡片或标签上获得的入口站Hex编码，如：“1101ABCD”
         */
        public byte[] enTollStationHex = new byte[9];
        /**
         * 入口时间
         */
        public byte[] enPassTime = new byte[20];
        /**
         * 卡片或标签上获得的上一收费门架的HEX编码，如“1101AB”。（同一个收费单元的前后两个门架的HEX编码是相同的，所以实际上HEX编码与收费单元一一对应。）
         */
        public byte[] lastGantryHex = new byte[7];
        /**
         * 卡片或标签上获得的经过上一收费门架的时间
         */
        public byte[] lastPasstime = new byte[20];
        /**
         * CPC卡EF02文件中上个门架的计费金额，单位：分，ETC无定义
         */
        public int lastGantryFee;
        /**
         * CPC卡EF02文件中上个门架的计费里程，单位：M（米），ETC无定义
         */
        public int lastFeeMileage;
        /**
         * 发行服务机构编码，如四川工行：“510102”,CPC卡填“0”。
         */
        public byte[] issuerId = new byte[7];
        /**
         * 卡网络编号：如“4401”，CPC卡填“0”。
         */
        public byte[] cardNetwork = new byte[5];
        /**
         * 车辆用户类型（CPU卡0015文件或单片式标签EF01） 0-普通车；6-公务车；8-军警车；10-紧急车；12-免费；14-车队；0～20内其他：自定义；
         * 对于道路运输证经营范围为“货物专用运输（集装箱）”且不含“普通货运”的牵引车、集装箱车定义为：Ox18，其他牵引车定义为：OxlB；
         * 应急救援车辆定义为： OxlA。
         */
        public int vehicleUserType;
        /**
         * 车辆轴数，CPC卡从DF01目录下EF01文件获取；电子标签填入 0。
         */
        public int axleCount;
        /**
         * 入口车辆轴数，入口写入的车辆轴数。CPC卡从DF01目录EF01获取；单片式标签从EF02获取，双片式标签从CPU卡0019文件获取。
         */
        public int enAxleCount;
        /**
         * 0-单片式标签 1-双片式ETC卡 2-CPC卡
         */
        public int tagType;
        /**
         * 卡片类型，见CPU卡0015文件第9字节。非双片式或双片式标签无卡时填0。如：储值卡为22。
         */
        public int cardType;
        /**
         * 卡片版本号，见CPU卡0015文件第10字节。非双片式时填0。如：0x04。
         */
        public int cardVer;
        /**
         * OBU/CPC序号编码。OBU的EF01系统信息文件的合同序列号；CPC的EF01系统信息文件的CPC卡ID。如OBU ID号：4401123456789012。
         */
        public byte[] obuSn = new byte[17];
        /**
         * 双片式ETC卡号，如CPU卡：44011234567890123456
         */
        public byte[] cpuCardId = new byte[21];
        /**
         * 车牌号（16进制字符串格式）。
         * 卡签中读得的12字节车牌号扩展成24字节的16进制字符串。
         * 如：卡签中读得的GB2312编码的车牌“京A12345”时该字段填“BEA941313233343500000000”。
         */
        public byte[] plateHex = new byte[25];
        /**
         * 车牌颜色：高字节：0x00
         * 低字节：0x00 –蓝色；0x01–黄色；0x02 –黑色；
         * 0x03 –白色；0x04-渐变绿色；0x05-黄绿双拼色； 0x06-蓝白渐变；0x07～0xFF保留。如0x0001表示黄色。
         */
        public short plateColor;
        /**
         * 车型，若为CPC卡读取DF01目录下的EF01车型；若为电子标签读取EF01车型。
         * EF01文件车型相关描述：
         * ①客车车型：
         * 0x01–一类客车；0x02–二类客车；0x03–三类客车；0x04–四类客车；0x05–五类客车；0x06–六类客车；0x07～0x0A–自定义
         * ②货车车型：0x0B–一类货车；0x0C–二类货车；0x0D–三类货车；0x0E–四类货车；0x0F–五类货车；0x10–六类货车；0x11～0x14–自定义
         * ③专项作业车车型：0x15–一类专项作业车；0x16–二类专项作业车；0x17–三类专项作业车；0x18–四类专项作业车；0x19–五类专项作业车；0x1A–六类专项作业车；
         * 0x1B～0xFF–保留。
         * 注：若为牵引车，该字段写入牵引车车型。
         */
        public int vehicleType;
        /**
         * 入口信息中的车型，双片式标签从0019文件获得，单片式标签从EF02文件获得，CPC从DF01目录下的EF01文件获得。
         */
        public int enVehicleType;
        /**
         * 车种（仅CPC卡有效）
         * 0-普通车；6-公务车；8-军警车；10-紧急车；12-免费；14-车队；0~20内其他：自定义应用； 21-绿通车；22-联合收割机
         * 23-抢险救灾24-集装箱车 25-大件运输 26-应急保障车 27-货车列车或半挂汽车列车；28~255保留。
         */
        public int vehicleClass;
        /**
         * ETC 储值卡当前卡面余额；CPC 无定义。
         */
        public int feeSumLocal;
        /**
         * 车辆限定载质量/座位数/准牵引总质量。由客车电子标签EFO1中车辆限定载重/座位数获得，由货车电子标签EF01中车辆核定载质量／准牵引总质量获得，质量单位为kg。CPC卡填0。
         */
        public int vehicleWeightLimits;
        /**
         * 货车总重，单位：kg。总重信息双片式从0019文件获得，单片式标签从EF02文件获得，CPC从DF01目录下的EF01文件获得。
         */
        public int totalWeight;
        /**
         * 车辆状态标识，从入口写入的文件中获得。车辆本次通行状态标识，
         * OxOO -本次通行用于大件运输；OxOl -非优惠车辆； Ox02 -绿通车辆； Ox03 -联合收割机车辆； Ox04 -集装箱车辆。Ox05-0xFE -保留
         * 注：可选填，默认写入OxFF。
         */
        public int vehicleStatusFlag;
        /**
         * 本省入口ETC门架信息，（省界入口ETC门架或省内第一个ETC门架的6位HEX编码，收费站入口格式为“000000”），默认值为空表示此字段无效。
         */
        public byte[] feeProvBeginHex = new byte[9];
        /**
         * 本省累计计费里程，单位：M（米），
         * 默认值-1 表示此字段无效。
         */
        public int feeProvMileage;
        /**
         * ETC 标签 EF04 文件中读出的本省累计交易成功次数；CPC EF02 文件中读出的本省门架个数，默认值-1 表示此字段无效。
         */
        public int feeProvGantryNum;
        /**
         * ETC 标签 EF04 文件中读出的本省累计应收金额；CPC 卡 EF02 文件中读出的本省累计金额，单位：分，默认填-1 表示此字段无效。
         */
        public int payFeeSumLocal;
        /**
         * ETC 标签 EF04 文件中读出的本省累计实收金额，单位：分，默认填-1 表示此字段无效。
         */
        public int realFeeSumLocal;
        /**
         * CPC 卡 EF02 文件中过站信息中写入的门架数量，ETC 默认为 0
         */
        public int gantryPassNum;
        /**
         * CPC 卡 EF02 文件中过站信息，如本门架之前经过 295F03，295F04 两个门架，则内容为：“295F03295F04”，ETC 默认为空
         */
        public byte[] gantryPassHex = new byte[145];
        /**
         * 计费模块保留输入字段 1
         */
        public int Spare1;
        /**
         * 计费模块保留输入字段 2
         */
        public int Spare2;
        /**
         * 计费模块保留输入字段 3
         */
        public int Spare3;
        /**
         * 计费模块保留输入字段 4,不支持汉字
         */
        public byte[] Spare4 = new byte[50];
        /**
         * 计费模块保留输入字段 5,不支持汉字
         */
        public byte[] Spare5 = new byte[200];

        public static class ByReference extends TradingInfo implements Structure.ByReference {
        }

        public static class ByValue extends TradingInfo implements Structure.ByValue {
        }

        public TradingInfo() {
            super(ALIGN_NONE);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[]{
                    "curTollGantry",
                    "curPassTime",
                    "laneStatus",
                    "enTollStationHex",
                    "enPassTime",
                    "lastGantryHex",
                    "lastPasstime",
                    "lastGantryFee",
                    "lastFeeMileage",
                    "issuerId",
                    "cardNetwork",
                    "vehicleUserType",
                    "axleCount",
                    "enAxleCount",
                    "tagType",
                    "cardType",
                    "cardVer",
                    "obuSn",
                    "cpuCardId",
                    "plateHex",
                    "plateColor",
                    "vehicleType",
                    "enVehicleType",
                    "vehicleClass",
                    "feeSumLocal",
                    "vehicleWeightLimits",
                    "totalWeight",
                    "vehicleStatusFlag",
                    "feeProvBeginHex",
                    "feeProvMileage",
                    "feeProvGantryNum",
                    "payFeeSumLocal",
                    "realFeeSumLocal",
                    "gantryPassNum",
                    "gantryPassHex",
                    "Spare1",
                    "Spare2",
                    "Spare3",
                    "Spare4",
                    "Spare5"
            });
        }

        @Override
        public String toString() {
            return "TradingInfo{" +
                    "curTollGantry=" + new String(curTollGantry).trim() +
                    ", curPassTime=" + new String(curPassTime).trim() +
                    ", laneStatus=" + laneStatus +
                    ", enTollStationHex=" + new String(enTollStationHex).trim() +
                    ", enPassTime=" + new String(enPassTime).trim() +
                    ", lastGantryHex=" + new String(lastGantryHex).trim() +
                    ", lastPasstime=" + new String(lastPasstime).trim() +
                    ", lastGantryFee=" + lastGantryFee +
                    ", lastFeeMileage=" + lastFeeMileage +
                    ", issuerId=" + new String(issuerId).trim() +
                    ", cardNetwork=" + new String(cardNetwork).trim() +
                    ", vehicleUserType=" + vehicleUserType +
                    ", axleCount=" + axleCount +
                    ", enAxleCount=" + enAxleCount +
                    ", tagType=" + tagType +
                    ", cardType=" + cardType +
                    ", cardVer=" + cardVer +
                    ", obuSn=" + new String(obuSn).trim() +
                    ", cpuCardId=" + new String(cpuCardId).trim() +
                    ", plateHex=" + new String(plateHex).trim() +
                    ", plateColor=" + plateColor +
                    ", vehicleType=" + vehicleType +
                    ", enVehicleType=" + enVehicleType +
                    ", vehicleClass=" + vehicleClass +
                    ", feeSumLocal=" + feeSumLocal +
                    ", vehicleWeightLimits=" + vehicleWeightLimits +
                    ", totalWeight=" + totalWeight +
                    ", vehicleStatusFlag=" + vehicleStatusFlag +
                    ", feeProvBeginHex=" + new String(feeProvBeginHex).trim() +
                    ", feeProvMileage=" + feeProvMileage +
                    ", feeProvGantryNum=" + feeProvGantryNum +
                    ", payFeeSumLocal=" + payFeeSumLocal +
                    ", realFeeSumLocal=" + realFeeSumLocal +
                    ", gantryPassNum=" + gantryPassNum +
                    ", gantryPassHex=" + new String(gantryPassHex).trim() +
                    ", Spare1=" + Spare1 +
                    ", Spare2=" + Spare2 +
                    ", Spare3=" + Spare3 +
                    ", Spare4=" + new String(Spare4).trim() +
                    ", Spare5=" + new String(Spare5).trim() +
                    "} ";
        }
    }

    public static class FeeInfo extends Structure {
        /**
         * 应收金额，单位：分
         */
        public int payFee;
        /**
         * 优惠金额，单位：分
         */
        public int discountFee;
        /**
         * //实收金额，单位：分
         */
        public int realFee;
        /**
         * ETC 卡面扣款金额（ETC 用户卡电子钱包扣款金额）；
         * CPC 卡面计费金额（只含本门架计费金额和代收门架金额，不包含拟合前序门架金额，同时用于写入 EF02 过站信息文件中最新门架计费金额），
         * 单位：分（注：旧版本字段名为fee，仅进行字段名修改但用途未变，避免与交易流水中字段 fee 混肴）
         */
        public int cardFee;
        /**
         * ETC 表示本省累计实收金额（含本门架实收金额，即标签 EF04 文件中本省累计实收金额）；
         * CPC 表示本省累计金额（含本门架计费金额，即 EF02 过站信息文件的本省累计计金额），单位：分。
         */
        public int feeProvSumLocal;
        /**
         * 计费参数版本，格式为“2位省份编码+yyyymmdd+3位顺序号”
         * paramVersion[14]
         */
        public byte[] paramVersion = new byte[14];
        /**
         * 计费特情组合，无特情值时为空，详细定义见“9.费率信息特情值定义” 多种特情以“|”分隔。
         */
        public byte[] feeSpecial = new byte[50];
        /**
         * 本门架拟合结果 0-未拟合或拟合成功 1-拟合失败。
         */
        public int fitResult;
        /**
         * 收费单元编号+处理标识，用于ETC复合消费或者CPC计费，若有代收或者拟合用“|”间隔，
         * 其中处理标识定义为
         * 0-默认
         * 1-本门架
         * 2-没有前序门架的代收（代收门架为未建设或维护抢修）
         * 3-拟合前序门架的代收（“上个门架-代收门架-本门架”的路径可确定为唯一路径）
         * 4-最短路径处理
         * 5-最小费额处理，
         * 如：“G0015320030015201|G0015320030015203”
         * tollIntervalIDs[851]
         */
        public byte[] tollIntervalIDs = new byte[1080];
        /**
         * 收费单元应收金额（优惠前金额）组合，用于 ETC 或者 CPC 计费，单位：分，若有代收或者拟合用“|”分隔。
         * 如 ：“1000|2000” 表示按照 tollIntervalIDs 中先后出现的两个收费单元分别应收费（优惠前）10 元和 20 元。
         */
        public byte[] payFeeGroup = new byte[401];
        /**
         * 收费单元优惠金额组合，用于ETC复合消费或者CPC计费，单位：分，若有代收或者拟合用“|”分隔。
         * 如 ：“200|700”表示按照tollIntervalIDs中先后出现的两个收费单元分别应优惠2元和7元。
         * discountFeeGroup[401]
         */
        public byte[] discountFeeGroup = new byte[401];
        /**
         * 交易金额（应收金额减去优惠金额）组合，用于ETC复合消费或者CPC计费，单位：分，若有代收或者拟合用“|”分隔。
         * 如 ：“800|1300”表示按照tollIntervalIDs中先后出现的两个收费单元交易金额分别为8元和13元。
         * feeGroup[401]
         */
        public byte[] feeGroup = new byte[401];
        /**
         * 计费信息1，省份自定义，ASCII编码（不支持汉字）计费模块可以使用自定义字段(计费信息1、2、3)返回优惠率、优惠类型及说明、错误码或特情等信息，
         * 该信息会在交易流水中上传省中心，用于省中心的自定义分析。推荐参照前面字段的样式。
         * feeInfo1[401]
         */
        public byte[] feeInfo1 = new byte[401];
        /**
         * 计费信息2，省份自定义，ASCII编码（不支持汉字）
         * feeInfo2[401]
         */
        public byte[] feeInfo2 = new byte[401];
        /**
         * 计费信息3，省份自定义，ASCII编码（不支持字）
         * feeInfo3[401]
         */
        public byte[] feeInfo3 = new byte[401];
        /**
         * 计费模块中不写日志，若有需要通过该字段返回信息，门架系统写日志，ASCII编码（不支持汉字）
         * feeLogMsg[501]
         */
        public byte[] feeLogMsg = new byte[501];
        /**
         * 计费模块实际使用的车型，计费模块可根据此字段返回本次交易使用的车型，车型相关描述：
         * ①客车车型：0x01–一类客车；0x02–二类客车；0x03–三类客车；0x04–四类客车；0x05–五类客车；0x06–六类客车；0x07～0x0A–自定义
         * ②货车车型：0x0B–一类货车；0x0C–二类货车；0x0D–三类货车；0x0E–四类货车；0x0F–五类货车；0x10–六类货车；0x11～0x14–自定义
         * ③专项作业车车型：0x15–一类专项作业车；0x16–二类专项作业车；0x17–三类专项作业车；0x18–四类专项作业车；0x19–五类专项作业车；0x1A–六类专项作业车；
         * 0x1B～0xFF–保留。注：若为牵引车，该字段写入牵引车车型。
         */
        public int feeVehicleType;
        /**
         * 本次计费里程，单位：M（米）， 默认写0
         */
        public int feeMileage;
        /**
         * 省界出口计费模块可根据本省计费起点（见7.2费率信息的feeProvBeginHex字段）按最短路径或者最小费额等方式输出用于参考的累计通行金额，供异常分析使用。
         * 格式为：计算方式+“|”+累加通行金额；计算方式：1-最短路径 2-最小费额 3-其他，累加通行金额单位：分。例:1|88888，默认为空
         */
        public byte[] provMinFee = new byte[10];
        /**
         * 拟合后的本省省界入口 ETC 门架HEX 码。本省省界入口漏交易或交易失败的情况下，满足条件的省份可以拟合出本省省界入口，
         * 门架将其写入标签 EF04 或 CPC 卡 EF02 文件中的本省入口门架信息中，无需拟合或拟合失败填空。
         */
        public byte[] feeProvBeginHexFit = new byte[9];
        /**
         * 拟合后的本省省界入口 ETC 门 架的通行时间，此时间需在上个门架的通行时间（输入参数 lastPasstime）与当前时间之间，
         * 如：“2020-03-20T15:32:58”，门架将其写入 CPC 卡 EF02 文件中的本省入口门架信息中，无需拟合或拟合失败填空。
         */
        public byte[] feeProvBeginTimeFit = new byte[20];
        /**
         * CPC 卡是否进行全省路径拟合的标识，0-未拟合，大于 0的值省内自行定义拟合方式。
         * 此值为0时，以下 gantryPassNumFit ，gantryPassHexFit，2个字段均视为无效。
         */
        public int fitProvFlag;
        /**
         * CPC 卡进行全省路径拟合后的过站信息 EF02 文件的过站信息中写入的门架数量。
         * 最多24个门架。门架软件将此值写入到 EF02文件中的第29字节。
         */
        public int gantryPassNumFit;
        /**
         * CPC 卡进行全省路径拟合后的过站信息 EF02 文件中过站信息，如经过处理后还原出 295F03，295F05 两个门架，则内容为：“295F03295F05”。
         * 门架软件将此过站信息覆盖写入到 EF02 文件中的 30-101 字节。
         */
        public byte[] gantryPassHexFit = new byte[145];
        /**
         * ETC 表示本省累计应收金额（含本门架应收金额，即标签 EF04 文件中本省累计应收金额），
         * CPC 表示本省累计拆分金额（含本门架计费金额，即 EF04 省份计费信息的本省累计计费金额），
         * 单位：分
         */
        public int feeSpare1;
        /**
         * 本省累计计费里程（含本门架计费里程），单位：M（米）
         */
        public int feeSpare2;
        /**
         * 计费模块保留输出字段3,不支持中文
         */
        public byte[] feeSpare3 = new byte[50];

        public static class ByReference extends FeeInfo implements Structure.ByReference {
        }

        public static class ByValue extends FeeInfo implements Structure.ByValue {
        }

        public FeeInfo() {
            super(ALIGN_NONE);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[]{
                    "payFee",
                    "discountFee",
                    "realFee",
                    "cardFee",
                    "feeProvSumLocal",
                    "paramVersion",
                    "feeSpecial",
                    "fitResult",
                    "tollIntervalIDs",
                    "payFeeGroup",
                    "discountFeeGroup",
                    "feeGroup",
                    "feeInfo1",
                    "feeInfo2",
                    "feeInfo3",
                    "feeLogMsg",
                    "feeVehicleType",
                    "feeMileage",
                    "provMinFee",
                    "feeProvBeginHexFit",
                    "feeProvBeginTimeFit",
                    "fitProvFlag",
                    "gantryPassNumFit",
                    "gantryPassHexFit",
                    "feeSpare1",
                    "feeSpare2",
                    "feeSpare3"

            });
        }

        @Override
        public String toString() {
            return "FeeInfo{" +
                    "payFee=" + payFee +
                    ", discountFee=" + discountFee +
                    ", realFee=" + realFee +
                    ", cardFee=" + cardFee +
                    ", feeProvSumLocal=" + feeProvSumLocal +
                    ", paramVersion=" + new String(paramVersion).trim() +
                    ", feeSpecial=" + new String(feeSpecial).trim() +
                    ", fitResult=" + fitResult +
                    ", tollIntervalIDs=" + new String(tollIntervalIDs).trim() +
                    ", payFeeGroup=" + new String(payFeeGroup).trim() +
                    ", discountFeeGroup=" + new String(discountFeeGroup).trim() +
                    ", feeGroup=" + new String(feeGroup).trim() +
                    ", feeInfo1=" + new String(feeInfo1).trim() +
                    ", feeInfo2=" + new String(feeInfo2).trim() +
                    ", feeInfo3=" + new String(feeInfo3).trim() +
                    ", feeLogMsg=" + new String(feeLogMsg).trim() +
                    ", feeVehicleType=" + feeVehicleType +
                    ", feeMileage=" + feeMileage +
                    ", provMinFee=" + new String(provMinFee).trim() +
                    ", feeProvBeginHexFit=" + new String(feeProvBeginHexFit).trim() +
                    ", feeProvBeginTimeFit=" + new String(feeProvBeginTimeFit).trim() +
                    ", fitProvFlag=" + fitProvFlag +
                    ", gantryPassNumFit=" + gantryPassNumFit +
                    ", gantryPassHexFit=" + new String(gantryPassHexFit).trim() +
                    ", feeSpare1=" + feeSpare1 +
                    ", feeSpare2=" + feeSpare2 +
                    ", feeSpare3=" + new String(feeSpare3).trim() +
                    "} ";
        }
    }

    public static class FeeInfoByHex extends Structure {
        /**
         * 应收金额，单位：分
         */
        public int payFee;
        /**
         * 优惠金额，单位：分
         */
        public int discountFee;
        /**
         * //实收金额，单位：分
         */
        public int realFee;
        /**
         * ETC 卡面扣款金额（ETC 用户卡电子钱包扣款金额）；
         * CPC 卡面计费金额（只含本门架计费金额和代收门架金额，不包含拟合前序门架金额，同时用于写入 EF02 过站信息文件中最新门架计费金额），
         * 单位：分（注：旧版本字段名为fee，仅进行字段名修改但用途未变，避免与交易流水中字段 fee 混肴）
         */
        public int cardFee;
        /**
         * ETC 表示本省累计实收金额（含本门架实收金额，即标签 EF04 文件中本省累计实收金额）；
         * CPC 表示本省累计金额（含本门架计费金额，即 EF02 过站信息文件的本省累计计金额），单位：分。
         */
        public int feeProvSumLocal;
        /**
         * 计费参数版本，格式为“2位省份编码+yyyymmdd+3位顺序号”
         * paramVersion[14]
         */
        public byte[] paramVersion = new byte[14];
        /**
         * 计费特情组合，无特情值时为空，详细定义见“9.费率信息特情值定义” 多种特情以“|”分隔。
         */
        public byte[] feeSpecial = new byte[50];
        /**
         * 本门架拟合结果 0-未拟合或拟合成功 1-拟合失败。
         */
        public int fitResult;
        /**
         * 收费单元编号+处理标识，用于ETC复合消费或者CPC计费，若有代收或者拟合用“|”间隔，
         * 其中处理标识定义为
         * 0-默认
         * 1-本门架
         * 2-没有前序门架的代收（代收门架为未建设或维护抢修）
         * 3-拟合前序门架的代收（“上个门架-代收门架-本门架”的路径可确定为唯一路径）
         * 4-最短路径处理
         * 5-最小费额处理，
         * 如：“G0015320030015201|G0015320030015203”
         * tollIntervalIDs[851]
         */
        public byte[] tollIntervalIDs = new byte[5400];
        /**
         * 收费单元应收金额（优惠前金额）组合，用于 ETC 或者 CPC 计费，单位：分，若有代收或者拟合用“|”分隔。
         * 如 ：“1000|2000” 表示按照 tollIntervalIDs 中先后出现的两个收费单元分别应收费（优惠前）10 元和 20 元。
         */
        public byte[] payFeeGroup = new byte[1800];
        /**
         * 收费单元优惠金额组合，用于ETC复合消费或者CPC计费，单位：分，若有代收或者拟合用“|”分隔。
         * 如 ：“200|700”表示按照tollIntervalIDs中先后出现的两个收费单元分别应优惠2元和7元。
         * discountFeeGroup[401]
         */
        public byte[] discountFeeGroup = new byte[1800];
        /**
         * 交易金额（应收金额减去优惠金额）组合，用于ETC复合消费或者CPC计费，单位：分，若有代收或者拟合用“|”分隔。
         * 如 ：“800|1300”表示按照tollIntervalIDs中先后出现的两个收费单元交易金额分别为8元和13元。
         * feeGroup[401]
         */
        public byte[] feeGroup = new byte[1800];
        /**
         * 计费信息1，省份自定义，ASCII编码（不支持汉字）计费模块可以使用自定义字段(计费信息1、2、3)返回优惠率、优惠类型及说明、错误码或特情等信息，
         * 该信息会在交易流水中上传省中心，用于省中心的自定义分析。推荐参照前面字段的样式。
         * feeInfo1[401]
         */
        public byte[] feeInfo1 = new byte[401];
        /**
         * 计费信息2，省份自定义，ASCII编码（不支持汉字）
         * feeInfo2[401]
         */
        public byte[] feeInfo2 = new byte[401];
        /**
         * 计费信息3，省份自定义，ASCII编码（不支持字）
         * feeInfo3[401]
         */
        public byte[] feeInfo3 = new byte[401];
        /**
         * 计费模块中不写日志，若有需要通过该字段返回信息，门架系统写日志，ASCII编码（不支持汉字）
         * feeLogMsg[501]
         */
        public byte[] feeLogMsg = new byte[501];
        /**
         * 计费模块实际使用的车型，计费模块可根据此字段返回本次交易使用的车型，车型相关描述：
         * ①客车车型：0x01–一类客车；0x02–二类客车；0x03–三类客车；0x04–四类客车；0x05–五类客车；0x06–六类客车；0x07～0x0A–自定义
         * ②货车车型：0x0B–一类货车；0x0C–二类货车；0x0D–三类货车；0x0E–四类货车；0x0F–五类货车；0x10–六类货车；0x11～0x14–自定义
         * ③专项作业车车型：0x15–一类专项作业车；0x16–二类专项作业车；0x17–三类专项作业车；0x18–四类专项作业车；0x19–五类专项作业车；0x1A–六类专项作业车；
         * 0x1B～0xFF–保留。注：若为牵引车，该字段写入牵引车车型。
         */
        public int feeVehicleType;
        /**
         * 本次计费里程，单位：M（米）， 默认写0
         */
        public int feeMileage;
        /**
         * 省界出口计费模块可根据本省计费起点（见7.2费率信息的feeProvBeginHex字段）按最短路径或者最小费额等方式输出用于参考的累计通行金额，供异常分析使用。
         * 格式为：计算方式+“|”+累加通行金额；计算方式：1-最短路径 2-最小费额 3-其他，累加通行金额单位：分。例:1|88888，默认为空
         */
        public byte[] provMinFee = new byte[10];

        /**
         * 拟合后的本省省界入口 ETC门架HEX码。本省省界入口漏交易或交易失败的情况下，满足条件的省份可以拟合出本省省界入口，
         * 门架将其写入标签 EF04 或 CPC 卡 EF02 文件中的本省入口门架信息中，无需拟合或拟合失败填空。
         */
        public byte[] feeProvBeginHexFit = new byte[9];
        /**
         * 拟合后的本省省界入口ETC门架的通行时间，此时间需在上个门架的通行时间（输入参数 lastPasstime）与当前时间之间，
         * 如：“2020-03-20T15:32:58”，门架将其写入CPC卡EF02文件中的本省入口门架信息中，无需拟合或拟合失败填空。
         */
        public byte[] feeProvBeginTimeFit = new byte[20];
        /**
         * CPC 卡是否进行全省路径拟合的标识，0-未拟合，大于 0的值省内自行定义拟合方式。
         * 此值为0时，以下 gantryPassNumFit ，gantryPassHexFit，2个字段均视为无效。
         */
        public int fitProvFlag;
        /**
         * CPC 卡进行全省路径拟合后的过站信息 EF02 文件的过站信息中写入的门架数量。
         * 最多24个门架。门架软件将此值写入到 EF02文件中的第29字节。
         */
        public int gantryPassNumFit;

        /**
         * CPC 卡进行全省路径拟合后的过站信息 EF02 文件中过站信息，如经过处理后还原出 295F03，295F05 两个门架，则内容为：“295F03295F05”。
         * 门架软件将此过站信息覆盖写入到 EF02 文件中的 30-101 字节。
         */
        public byte[] gantryPassHexFit = new byte[145];
        /**
         * ETC 表示本省累计应收金额（含本门架应收金额，即标签 EF04 文件中本省累计应收金额），
         * CPC 表示本省累计拆分金额（含本门架计费金额，即 EF04 省份计费信息的本省累计计费金额），
         * 单位：分
         */
        public int feeSpare1;
        /**
         * 本省累计计费里程（含本门架计费里程），单位：M（米）
         */
        public int feeSpare2;
        /**
         * 计费模块保留输出字段3,不支持中文
         */
        public byte[] feeSpare3 = new byte[50];

        public static class ByReference extends FeeInfoByHex implements Structure.ByReference {
        }

        public static class ByValue extends FeeInfoByHex implements Structure.ByValue {
        }

        public FeeInfoByHex() {
            super(ALIGN_NONE);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList(new String[]{
                    "payFee",
                    "discountFee",
                    "realFee",
                    "cardFee",
                    "feeProvSumLocal",
                    "paramVersion",
                    "feeSpecial",
                    "fitResult",
                    "tollIntervalIDs",
                    "payFeeGroup",
                    "discountFeeGroup",
                    "feeGroup",
                    "feeInfo1",
                    "feeInfo2",
                    "feeInfo3",
                    "feeLogMsg",
                    "feeVehicleType",
                    "feeMileage",
                    "provMinFee",
                    "feeProvBeginHexFit",
                    "feeProvBeginTimeFit",
                    "fitProvFlag",
                    "gantryPassNumFit",
                    "gantryPassHexFit",
                    "feeSpare1",
                    "feeSpare2",
                    "feeSpare3"

            });
        }

        @Override
        public String toString() {
            return "FeeInfoByHex{" +
                    "payFee=" + payFee +
                    ", discountFee=" + discountFee +
                    ", realFee=" + realFee +
                    ", cardFee=" + cardFee +
                    ", feeProvSumLocal=" + feeProvSumLocal +
                    ", paramVersion=" + new String(paramVersion).trim() +
                    ", feeSpecial=" + new String(feeSpecial).trim() +
                    ", fitResult=" + fitResult +
                    ", tollIntervalIDs=" + new String(tollIntervalIDs).trim() +
                    ", payFeeGroup=" + new String(payFeeGroup).trim() +
                    ", discountFeeGroup=" + new String(discountFeeGroup).trim() +
                    ", feeGroup=" + new String(feeGroup).trim() +
                    ", feeInfo1=" + new String(feeInfo1).trim() +
                    ", feeInfo2=" + new String(feeInfo2).trim() +
                    ", feeInfo3=" + new String(feeInfo3).trim() +
                    ", feeLogMsg=" + new String(feeLogMsg).trim() +
                    ", feeVehicleType=" + feeVehicleType +
                    ", feeMileage=" + feeMileage +
                    ", provMinFee=" + new String(provMinFee).trim() +
                    ", feeProvBeginHexFit=" + new String(feeProvBeginHexFit).trim() +
                    ", feeProvBeginTimeFit=" + new String(feeProvBeginTimeFit).trim() +
                    ", fitProvFlag=" + fitProvFlag +
                    ", gantryPassNumFit=" + gantryPassNumFit +
                    ", gantryPassHexFit=" + new String(gantryPassHexFit).trim() +
                    ", feeSpare1=" + feeSpare1 +
                    ", feeSpare2=" + feeSpare2 +
                    ", feeSpare3=" + new String(feeSpare3).trim() +
                    "} ";
        }
    }

//    /**
//     *
//     * @param tradingInfo
//     * @param feeInfo
//     * @return
//     */
//    int getFeeWithPathByHex(TradingInfo.ByReference tradingInfo, FeeInfoByHex.ByReference feeInfoByHex);
}
